package tp.pr3;

import tp.pr3.instructions.Instruction;
import tp.pr3.instructions.exceptions.InstructionExecutionException;
import tp.pr3.instructions.exceptions.WrongInstructionFormatException;
import tp.pr3.items.ItemContainer;
import tp.pr3.util.Messages;

public class RobotEngine {
	
	/**
	 * 
	 * @param initialPlace sitio desde donde se parte
	 * @param direction	dirección inicial
	 * @param cityMap mapa de la ciudad
	 */
	public RobotEngine (City cityMap, Place initialPlace, Direction direction) {
		this.fuel = FUEL_INITIAL;
		this.points = POINTS_INITIAL;
		this.pocket = new ItemContainer();
		this.gps = new NavigationModule(cityMap, initialPlace);
	}
	
	/**
	 * The robot says a message
	 * @param message
	 */
	public void robotSays(String message) {
		System.out.println(Messages.ROBOT_NAME + Messages.OUTPUT_SAYS + message);
	}
	/**
	 * The robot says a message (on system.err)
	 * @param message
	 */
	public void robotErrs(String message) {
		//System.err.println(Messages.ROBOT_NAME + Messages.OUTPUT_SAYS + message);
		System.out.println(Messages.ROBOT_NAME + Messages.OUTPUT_SAYS + message);
	}
	/**
	 * Prints both the fuel level and recycled material amount
	 */
	public void printRobotState () { //pública porque la necesitan el fuel y el garbage al usarse
		System.out.println(Messages.OUTPUT_SAYFUEL + this.fuel + Interpreter.LINE_SEPARATOR + Messages.OUTPUT_SAYRM + this.points);
	}
	

	/**
	 * Adds an amount of fuel to the robot (it can be negative)
	 * @param fuel Amount of fuel added to the robot
	 */
	public void addFuel(int fuel) {
		this.fuel += fuel;
		if (this.fuel < 0) 
			this.fuel = 0;
		//if (this.fuel > FUEL_MAX)
		// 	this.fuel = FUEL_MAX;
	}
	/**
	 * Adds an amount of fuel to the robot (it can be negative)
	 * @param weight Amount of fuel added to the robot
	 */
	public void addRecycledMaterial (int weight) {
		points += weight;
	}
	/**
	 * for testing
	 * @return current fuel level
	 */
	public int getFuel() {
		return this.fuel;
	}	
	/**
	 * for testing
	 * @return current engine points
	 */
	public int getRecycledMaterial() {
		return this.points;
	}
	
	/**
	 * prints all info related to the robot status after a fuel consumption
	 * @param consumedFuel fuel that was consumed
	 */
	public void sayAndUpdateDataAfterFuelConsumingAction(int consumedFuel) {
		System.out.println(this.gps.getCurrentHeading().sayDirection());
		this.addFuel(consumedFuel);
		this.printRobotState();
	}	
	/**
	 * It executes an instruction. The instruction must be configured with the context before executing it. It controls the end of the simulation. If the execution of the instruction throws an exception, then the corresponding message is printed
	 * @param c The instruction to be executed
	 */
	public void communicateRobot(Instruction c) {
		c.configureContext(this, this.gps, this.pocket);
		try {
			c.execute();
		} catch (InstructionExecutionException ex) {
			this.robotErrs(ex.getMessage());
		}
	}

	/**
	 * Requests the end of the simulation
	 */
	public void requestQuit() {
		this.endSimulation = true;
	}
	/**
	 * Prints the information about all possible instructions
	 */
	public void requestHelp() {
		System.out.println(Interpreter.interpreterHelp());
	}
	
	
	/**
	 * It starts the robot engine. 
	 * Basically, it reads a line, the interpreter generates the corresponding instruction and executes it. 
	 * The simulation finishes when the robot arrives at the space ship, the user types "QUIT", or the robot runs out of fuel
	 */
	public void startEngine (){
		//inicializamos el interpreter, el escáner, y mostramos los datos de lugar de incio del robot
		java.util.Scanner sc = new java.util.Scanner(System.in);
		System.out.println(this.gps.getCurrentPlace().toString());
		System.out.println(this.gps.getCurrentHeading().sayDirection());
		this.printRobotState();
		

		while (!this.endSimulation) {
			//System.out.println("");
			System.out.print(Messages.PROMPT);
			try {
				Instruction instruction = Interpreter.generateInstruction(sc.nextLine()); //ya que ignoramos mayus y minus
				this.communicateRobot(instruction);
			} catch (WrongInstructionFormatException ex) {
				System.err.println(ex.getMessage());
				//this.robotErrs(ex.getMessage());
			}
			
			//TESTING System.out.println("---Orden: " + instruction.toString() + "---");
			
			if (this.gps.getCurrentPlace().isSpaceship()){
				robotSays(Messages.OUTPUT_ATSPACESHIP);
				this.endSimulation = true;
			}
			if (this.fuel == 0) {
				robotSays(Messages.OUTPUT_FUEL_NOFUEL);
				this.endSimulation = true;
			}
			
		}
		sc.close();
	}
	

	

	//constantes numéricas
	private static final int FUEL_INITIAL = 100;
	//private static final int FUEL_MAX = 9001;
	private static final int POINTS_INITIAL = 0;
	

	private int fuel;
	private int points;
	private ItemContainer pocket;
	private NavigationModule gps;
	
	private boolean endSimulation = false;
}
